using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

using Supremacy.Client.Interop;

namespace Supremacy.Client.Controls
{
    public class InfoCardWindow : Window, IInfoCardWindow
    {
        #region Fields
        private Matrix _transformToDevice;
        private InfoCardCloseReason _closeReason;
        #endregion

        #region Constructors and Finalizers
		[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
		static InfoCardWindow()
        {
            //DefaultStyleKeyProperty.OverrideMetadata(
            //    typeof(InfoCardWindow),
            //    new FrameworkPropertyMetadata(typeof(InfoCardWindow)));

            ShowInTaskbarProperty.OverrideMetadata(
                typeof(InfoCardWindow),
                new FrameworkPropertyMetadata(false));

            SizeToContentProperty.OverrideMetadata(
                typeof(InfoCardWindow),
                new FrameworkPropertyMetadata(SizeToContent.WidthAndHeight));

            WindowStyleProperty.OverrideMetadata(
                typeof(InfoCardWindow),
                new FrameworkPropertyMetadata(WindowStyle.None));

            ResizeModeProperty.OverrideMetadata(
                typeof(InfoCardWindow),
                new FrameworkPropertyMetadata(ResizeMode.NoResize));

            AllowsTransparencyProperty.OverrideMetadata(
                typeof(InfoCardWindow),
                new FrameworkPropertyMetadata(true));

            BackgroundProperty.OverrideMetadata(
                typeof(InfoCardWindow),
                new FrameworkPropertyMetadata(Brushes.Transparent));

		    EventManager.RegisterClassHandler(
		        typeof(InfoCard),
		        InfoCard.PinnedEvent,
		        (RoutedEventHandler)OnInfoCardPinned);

            EventManager.RegisterClassHandler(
                typeof(InfoCard),
                InfoCard.UnpinnedEvent,
                (RoutedEventHandler)OnInfoCardUnpinned);
        }

        private static void OnInfoCardPinned(object sender, RoutedEventArgs e)
        {
            var infoCard = (InfoCard)sender;
            if (infoCard == null)
                return;

            var window = InfoCardHost.GetInfoCardWindow(infoCard) as InfoCardWindow;
            if (window == null)
                return;
            window.ShowInTaskbar = true;
            window.Topmost = true;
        }

        private static void OnInfoCardUnpinned(object sender, RoutedEventArgs e)
        {
            var infoCard = (InfoCard)sender;
            if (infoCard == null)
                return;

            var window = InfoCardHost.GetInfoCardWindow(infoCard) as InfoCardWindow;
            if (window == null)
                return;

            window.ShowInTaskbar = false;
            window.Topmost = false;
        }

        public InfoCardWindow(InfoCardHost container)
        {
			if (container == null)
				throw new ArgumentNullException("container");

			InfoCardHost.SetInfoCardWindow(this, this);

		    this.WindowStyle = WindowStyle.None;
		    this.ResizeMode = ResizeMode.NoResize;
		    this.AllowsTransparency = true;
            this.Background = Brushes.Transparent;
            this.Width = 0;
            this.Height = 0;
            this.SizeToContent = SizeToContent.WidthAndHeight;

			this.InfoCardHost = container;
		    
            var ownerWindow = GetWindow(this.InfoCardSite);
            if (ownerWindow != null)
                this.Owner = ownerWindow;

            var infoCard = (InfoCard)container.Content;
            var location = container.Location ?? new Point(0, 0);

            _transformToDevice = Matrix.Identity;

            var targetWindow = GetWindow(infoCard.TargetElement);
            if (targetWindow != null)
            {
                _transformToDevice.OffsetX = targetWindow.Left;
                _transformToDevice.OffsetY = targetWindow.Top;
                location = _transformToDevice.Transform(location);
            }

            this.Setup(location);

            this.Loaded += OnLoaded;
		}
        #endregion

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            this.Loaded -= OnLoaded;
            InvalidateMeasure();
        }

        protected override void OnContentRendered(EventArgs e)
        {
            base.OnContentRendered(e);

            if (this.SizeToContent == SizeToContent.WidthAndHeight)
                this.SizeToContent = SizeToContent.Height;
        }

        #region IsClosing Property
        private static readonly DependencyPropertyKey IsClosingPropertyKey = DependencyProperty.RegisterReadOnly(
            "IsClosing",
            typeof(bool),
            typeof(InfoCardWindow),
            new FrameworkPropertyMetadata(false));

        public static readonly DependencyProperty IsClosingProperty = IsClosingPropertyKey.DependencyProperty;

        public bool IsClosing
        {
            get { return (bool)this.GetValue(IsClosingProperty); }
            private set { this.SetValue(IsClosingPropertyKey, value); }
        }
        #endregion

        #region Implementation of IInfoCardWindow
        public void Close(InfoCardCloseReason reason)
        {
            _closeReason = reason;

            this.Close();
        }

        public InfoCardSite InfoCardSite
        {
            get { return this.InfoCardHost.InfoCardSite; }
        }


        public Point Location
        {
            get
            {
                var location = new Point(this.Left, this.Top);
                var infoCard = this.InfoCardHost.Content as InfoCard;
                if (infoCard != null)
                {
                    var targetWindow = GetWindow(infoCard.TargetElement);
                    if (targetWindow != null)
                    {
                        _transformToDevice = Matrix.Identity;
                        _transformToDevice.OffsetX = targetWindow.Left;
                        _transformToDevice.OffsetY = targetWindow.Top;
                    }
                }
                location = _transformToDevice.Transform(location);
                return location;
            }
        }

        public InfoCardHost InfoCardHost
        {
            get { return this.Content as InfoCardHost; }
            private set { this.Content = value; }
        }

        public void Setup(Point? position)
        {
            if (!position.HasValue)
                return;
            this.Left = position.Value.X;
            this.Top = position.Value.Y;
        }

        public void SnapToScreen()
        {
            var bounds = NativeMethods.EnsureBoundsOnScreen(
                new Rect(
                    this.Left,
                    this.Top,
                    this.Width,
                    this.Height));

            if (this.Left != bounds.Left)
                this.Left = bounds.Left;
            if (this.Top != bounds.Top)
                this.Top = bounds.Top;
        }

        void IInfoCardWindow.DragMove()
        {
            this.DragMove();
        }
        #endregion

        #region Window Close Method Overrides
        protected override void OnDeactivated(EventArgs e)
        {
            base.OnDeactivated(e);

            var popup = this.InfoCardSite.GetInfoCardFromHost(this.InfoCardHost);
            if ((popup != null) && !popup.IsPinned)
                popup.Close();
        }

        protected override void OnClosed(EventArgs e)
        {
            var popupSite = this.InfoCardSite;
            if (popupSite != null)
            {
                var window = GetWindow(popupSite);
                if ((window != null) && !window.IsActive)
                    window.Activate();
            }

            this.InfoCardHost = null;

            base.OnClosed(e);

            BindingOperations.ClearAllBindings(this);

            this.IsClosing = false;
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            if (e.Cancel)
            {
                _closeReason = InfoCardCloseReason.InfoCardWindowClosed;
                return;
            }

            this.IsClosing = true;

            var cancel = false;

            var infoCardSite = this.InfoCardSite;
            if (infoCardSite != null)
            {
                var popup = infoCardSite.GetInfoCardFromHost(this.InfoCardHost);
                if (popup != null)
                    cancel |= !infoCardSite.Close(popup, _closeReason, false);
            }

            _closeReason = InfoCardCloseReason.InfoCardWindowClosed;

            if (!cancel)
            {
                this.Owner = null;
                return;
            }

            e.Cancel = true;
            this.IsClosing = false;
            return;
        }
        #endregion
    }
}